package section

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/backend/model"
	"mall/service/backend/rpc/internal/svc"
	"mall/service/backend/rpc/internal/utils/errorhandler"
	"mall/service/backend/rpc/types/backend"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetSectionByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetSectionByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSectionByIdLogic {
	return &GetSectionByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetSectionByIdLogic) GetSectionById(in *backend.BaseIdReq) (*backend.SectionInfo, error) {
	// logrus.Info(fmt.Sprintf("GetSectionById: %+v", in))
	// Id:11 Preload:"section:Id,Title,Subtitle,PicId,PicUrl;sectionProduct:SectionId,BrandId,CategoryId,ProductId" EagerLoad:"section:sectionProduct" VisitorId:10021 PlatformId:1

	if (in.Filter == nil || len(*in.Filter) == 0) && (in.Id == nil || *in.Id == 0) {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)
	// logrus.Info(fmt.Sprintf("GetSectionById preloadMap: %+v", preloadMap))
	// map[section:[Id Title Subtitle PicId PicUrl] sectionProduct:[SectionId BrandId CategoryId ProductId]]
	// logrus.Info(fmt.Sprintf("GetSectionById eagerLoadMap: %+v", eagerLoadMap))
	// map[section:[sectionProduct]]

	resp := &backend.SectionInfo{}
	sectionEntityName := model.RpcEntityNames.Section
	if _, ok := model.RpcEntityPreloadMap[sectionEntityName]; !ok {
		return resp, nil
	}

	sectionRepositoryName := model.RepositoryNames.Section
	columnMap, ok := model.RepositoryPreloadMap[sectionRepositoryName]
	if !ok {
		return resp, nil
	}

	var section *model.Section
	var sid uint64
	if in.Filter != nil && len(*in.Filter) > 0 {
		var selectCols []string
		if preloadFields, ok := preloadMap[sectionEntityName]; ok {
			selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
		}
		selectCols = append(selectCols, model.SectionColumns.Status)

		filterMap := modelx.ParseFilter(in.Filter, columnMap)
		logrus.Info(fmt.Sprintf("GetSectionById filterMap: %+v", filterMap))
		//
		if filterMap == nil {
			return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
		}

		if in.Id != nil && *in.Id > 0 {
			filterMap[model.SectionColumns.ID] = map[string][]any{
				"equalTo": {*in.Id},
			}
		}

		orderBy := modelx.ParseSorter(in.Sorter, columnMap)
		logrus.Info(fmt.Sprintf("GetSectionById orderBy: %s", orderBy))
		//

		if len(orderBy) == 0 {
			orderBy = model.SectionColumns.ID
		}

		res, _, err := l.svcCtx.Section.GetList(l.ctx, model.M{
			"pageSize": uint64(1),
			"orderBy":  orderBy,
			"select":   strings.Join(selectCols, ","),
		}, -1, filterMap)
		if err != nil {
			return nil, err
		}

		if len(res) == 0 {
			return resp, nil
		}

		section = res[0]
		sid = section.ID
	} else {
		data, err := l.svcCtx.Section.FindOne(l.ctx, *in.Id)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		section = data
		sid = data.ID
	}

	if section == nil {
		return resp, nil
	}

	if section.Status != uint8(globalkey.StatusEnabled) {
		return resp, nil
	}

	now := time.Now()
	if section.StartedAt.Valid && section.StartedAt.Time.After(now) {
		return resp, nil
	}

	if section.EndedAt.Valid && section.EndedAt.Time.Before(now) {
		return resp, nil
	}

	var media []*backend.MediaInfo
	subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
	if eagerLoadEntities, ok := eagerLoadMap[sectionEntityName]; ok {
		for _, entity := range eagerLoadEntities {
			if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
				subEntitySettingMap[entity] = entitySettingMap
			}
		}
	}

	backendMediaEntityName := model.RpcEntityNames.BackendMedia
	if _, ok := subEntitySettingMap[backendMediaEntityName]; ok {
		backendMediaRepositoryName := model.RepositoryNames.BackendMedia
		subPreloadFields, hasSubPreloadFields := preloadMap[backendMediaEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[backendMediaRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			var subSelectCols []string = modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.AttachmentRelationshipColumns.ObjectID] = map[string][]any{
				"equalTo": []any{sid},
			}
			subFilterMap[model.AttachmentRelationshipColumns.ObjectType] = map[string][]any{
				"equalTo": []any{globalkey.AttachmentLogTypeSection},
			}
			orderBy := model.AttachmentRelationshipColumns.AttachmentThumbnail + " DESC," +
				model.AttachmentRelationshipColumns.AttachmentOrder
			list, _, err := l.svcCtx.Section.GetMedia(l.ctx, model.M{
				"orderBy": orderBy,
				"select":  strings.Join(subSelectCols, ","),
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				for _, v := range list {
					media = append(media, &backend.MediaInfo{
						Uid:       pointy.GetPointer(v.RelationshipID),
						Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
						Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
						Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
						Uri:       pointy.GetPointer(v.AttachmentImageSource),
						Url:       pointy.GetPointer(v.AttachmentImageURL),
						AltText:   pointy.GetPointer(v.AttachmentImageAlt),
						MetaData:  pointy.GetPointer(v.AttachmentImageMeta),
					})
				}
			}
		}
	}

	sectionProductEntityName := model.RpcEntityNames.SectionProduct
	productIdMap := make(map[uint64]uint32)
	if _, ok := subEntitySettingMap[sectionProductEntityName]; ok {
		sectionProductRepositoryName := model.RepositoryNames.SectionProduct
		subPreloadFields, hasSubPreloadFields := preloadMap[sectionProductEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[sectionProductRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.SectionProductRelationshipColumns.SectionID] = map[string][]any{
				"equalTo": {sid},
			}
			list, _, err := l.svcCtx.Section.GetRelProductList(l.ctx, model.M{
				"select": strings.Join(subSelectCols, ","),
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				for _, v := range list {
					// Todo 将 id 类型写为常数
					if v.ProductID > 0 {
						productIdMap[v.ProductID] = uint32(1)
					} else if v.BrandID > 0 {
						productIdMap[v.BrandID] = uint32(2)
					} else if v.CategoryID > 0 {
						productIdMap[v.CategoryID] = uint32(3)
					}
				}
			}
		}
	}

	var sort *uint32
	if section.Sort != uint16(globalkey.SystemDefaultSort) {
		sort = pointy.GetPointer(uint32(section.Sort))
	}

	return &backend.SectionInfo{
		Id:           &section.ID,
		Type:         pointy.GetPointer(uint32(section.Type)),
		Title:        &section.Title,
		Subtitle:     &section.Subtitle,
		PicId:        &section.PicID,
		PicUrl:       &section.PicURL,
		Sort:         sort,
		Status:       pointy.GetPointer(uint32(section.Status)),
		CreatedAt:    pointy.GetPointer(modelx.FormatTime(section.CreatedAt, "")),
		UpdatedAt:    pointy.GetPointer(modelx.FormatTime(section.UpdatedAt, "")),
		DeletedAt:    pointy.GetPointer(modelx.FormatNullDotTime(section.DeletedAt, "")),
		ProductIdMap: productIdMap,
		Media:        media,
	}, nil
}
